package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.ArrayList;

import util.MyParser;

public class ServerProgram {
	private ReceiveMonitor serverRM;
	private ArrayList<Participant> pl;
	private ArrayList<ReceiveThread> rtl;
	private ArrayList<SessionThread> stl;
	private ServerSocket ss;
	private String[] wordlist;

	public ServerProgram(ReceiveMonitor serverRM, ArrayList<Participant> pl,
			ArrayList<ReceiveThread> rtl, ArrayList<SessionThread> stl,
			ServerSocket ss, String[] wordlist) {
		this.serverRM = serverRM;
		this.pl = pl;
		this.rtl = rtl;
		this.stl = stl;
		this.ss = ss;
		this.wordlist = wordlist;
	}

	public void startServer() {
		ConnectionThread ct = new ConnectionThread(pl, ss, 10, serverRM, rtl);
		ct.start();
		while (true) {
			String input = serverRM.getMessage();
			String message = MyParser.getMessage(input);
			Commands command = CommandParser.getServerCommands(message);
			if (MyParser.isGame(input)) {

				switch (command) {
				case NEWGAME:
					newGame(input);
					break;
				case JOINGAME:
					joinGame(input);
					break;
				case GETGAMES:
					getGames(input);
					break;
				case EXITGAME:
					leaveServer(input);
					break;
				case NAME:
					boolean changed = changeName(input);
					if (!changed) {
						ServerSend.sendToPlayer(pl, MyParser.getName(input),
								"Server" + MyParser.FIELD + MyParser.GAME
										+ MyParser.FIELD + "name");
					}
					break;
				case INVALID:
					invalid(input);
				}
			} else if (MyParser.isServerMessage(input)) {
				switch (command) {
				case ENDOFGAME:
					endGame(input);
					break;
				case EXITGAME:
					leaveGame(input);
					break;
				case INVALID:
					invalid(input);
				}
			}

		}

	}

	private void newGame(String input) {
		String writer = MyParser.getName(input);
		Participant p = null;
		ReceiveThread rt = null;
		String[] data = MyParser.getData(input);
		int players = 0;
		int rounds = 0;
		if (data == null || data.length < 2) {
			invalid(input);
		} else {

			try {
				players = Integer.parseInt(data[0]);
				rounds = Integer.parseInt(data[1]);
				for (int i = 0; i < pl.size(); i++) {
					if (pl.get(i).getName().equals(writer)) {
						p = pl.get(i);
						pl.remove(i);
					}
				}
				for (int i = 0; i < rtl.size(); i++) {
					if (rtl.get(i).getParticipant().equals(p)) {
						rt = rtl.get(i);
						rtl.remove(i);
					}
				}
				if (p != null && rt != null) {
					SessionThread st = new SessionThread(stl.size(), p,
							wordlist, rounds, rt, players, serverRM);
					st.start();
					stl.add(st);
					ServerSend.serverGameSendToAll(st.getParticpants(),
							getScoreList(st.getParticpants()));
				}
			} catch (NumberFormatException nfe) {
				invalid(input);
			}

		}

	}

	private void joinGame(String input) {
		String[] data = MyParser.getData(input);
		if (data == null) {
			invalid(input);
		} else {
			int sessionID = Integer.parseInt(data[0]);

			if (joinable(sessionID)) {
				String writer = MyParser.getName(input);
				Participant p = null;
				ReceiveThread rt = null;

				for (int i = 0; i < pl.size(); i++) {
					if (pl.get(i).getName().equals(writer)) {
						p = pl.get(i);
						pl.remove(i);
					}
				}
				for (int i = 0; i < rtl.size(); i++) {
					if (rtl.get(i).getParticipant().equals(p)) {
						rt = rtl.get(i);
						rtl.remove(i);
					}
				}
				p.resetScore();
				stl.get(sessionID).addParticipant(p, rt);

				ServerSend.serverGameSendToAll(stl.get(sessionID)
						.getParticpants(), getScoreList(stl.get(sessionID)
						.getParticpants()));
			}
		}

	}

	private void endGame(String input) {
		int threadID = Integer.parseInt(MyParser.getName(input));
		for (int i = 0; i < stl.size(); i++) {
			if (stl.get(i).getID() == threadID) {

				pl.addAll(stl.get(i).getParticpants());
				rtl.addAll(stl.get(i).getReceiveThread());
				stl.remove(i);
			}
		}
	}

	private void getGames(String input) {
		String s = "server" + MyParser.FIELD + MyParser.GAME + MyParser.FIELD
				+ "games" + MyParser.FIELD + getJoinable();
		ServerSend.sendToPlayer(pl, MyParser.getName(input), s);
	}

	private void leaveGame(String input) {
		int sessionID = Integer.parseInt(MyParser.getData(input)[0]);
		String playerName = MyParser.getName(input);
		ArrayList<Participant> temp = stl.get(sessionID).getParticpants();
		for (int i = 0; i < temp.size(); i++) {
			Participant ptemp = temp.get(i);
			if (ptemp.getName().equals(playerName)) {
				stl.get(sessionID).getParticpants().remove(i);
				ReceiveThread rt = stl.get(sessionID).getReceiveThread().get(i);
				rt.setReceiveMonitor(serverRM);
				stl.get(sessionID).getReceiveThread().remove(i);

				pl.add(ptemp);
				rtl.add(rt);
			}
		}
	}

	private void leaveServer(String input) {
		String playerName = MyParser.getName(input);
		int index = 0;
		for (int i = 0; i < rtl.size(); i++) {
			if (rtl.get(i).getParticipant().getName().equals(playerName)) {
				index = i;
			}
		}
		ReceiveThread rt = rtl.remove(index);
		try {
			rt.getParticipant().getSocket().close();
		} catch (IOException e1) {
			System.out.println("Unable to close socket..");
		}
		pl.remove(rt.getParticipant());
	}

	private boolean changeName(String input) {
		String playerName = MyParser.getName(input);
		String newName = MyParser.getData(input)[0];
		int index = 0;
		for (int i = 0; i < pl.size(); i++) {
			Participant p = pl.get(i);
			if (p.getName().equals(playerName)) {
				index = i;
			} else if (p.getName().equals(newName)) {
				return false;
			}
		}
		pl.get(index).setName(newName);
		return true;
	}

	private void invalid(String input) {
	}

	private boolean joinable(int id) {
		if (id < stl.size()) {
			SessionThread st = stl.get(id);
			return !st.hasStarted() && !st.isFull();
		}
		return false;
	}

	private String getJoinable() {
		String s = "";
		if (stl.size() == 0) {
			s = "nogames";
			return s;
		} else {
			for (int i = 0; i < stl.size(); i++) {
				if (joinable(i))
					s = s + stl.get(i).getID() + MyParser.DATA;
			}
			if (s.equals("") || s.equals(MyParser.DATA))
				s = "nogames";
			return s;
		}
	}

	public String getScoreList(ArrayList<Participant> pl) {
		StringBuilder sb = new StringBuilder();
		sb.append("scores" + MyParser.FIELD);
		for (int i = 0; i < pl.size(); i++) {
			sb.append(pl.get(i).getName() + MyParser.DATA
					+ pl.get(i).getScore() + MyParser.DATA);
		}
		return sb.toString();
	}
}
